package widget.book
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import widget.book.utils.BookUtils;
	import widget.book.viewer.BasePageViewer;
	import widget.book.viewer.BookViewer;
	import widget.book.viewer.FlipMaskViewer;
	import widget.book.viewer.PageViewer;
	import widget.book.viewer.ShadowViewer;
	import widget.common.utils.MathUtils;

	public class BookFlip extends Sprite{
		
		public static var instance:Boolean=false;
		private var book:BookViewer = null;
		private var theNextPage:BasePageViewer = null;
		private var flipMasker	:FlipMaskViewer = null;
		private var shadow	:ShadowViewer = null;
		
		private var pageList:Vector.<BasePageViewer> = null;
		private var bWidth	:Number = 800;
		private var bHeight:Number = 600;
		
		private var isDraging:Boolean = false;
		private var isFlipping	:Boolean = false;
		private var isCorner:Boolean = false;
		private var isNext:Boolean = false;
		
		private var hotArea:Number = 0;
		private var preArea:Number = 0;
		private var mx	:Number = 0;
		private var my	:Number = 0;
		
		private var mousePoint:Point = null;
		private var topPoint:Point = null;
		private var botPoint:Point = null;
		private var targetPoint:Point = null;
		private var tempCenter:Point = null;
		
		private var tempRadius:Number = 0;
		private var radiusArray:Array = null;
		
		private var mouseSpeed:uint = 0;
		private var autoSpeed:uint = 0;
		private var flipSpeed:uint = 0;
		private var span:uint = 0;
		
		private var currentPageNum		:Number;
		private var nextPageNum			:Number;
		
		//------This parameters are for debug--------------
		private var debugMc				:DebugMC;
		private var pointArray			:Array;
		
		public function BookFlip()
		{
			if (instance) {
				throw Error("FlipBook类只能被实例化一次!");
			}else {
				instance = true;
			}
			
			book = new BookViewer(bWidth, bHeight);
			flipMasker = new FlipMaskViewer();
			shadow = new ShadowViewer();
			
			addChild(book);
			addChild(flipMasker);
			addChild(shadow);
			
			book.mask = flipMasker;
			
			configConst();
			addEventListener(Event.ADDED_TO_STAGE, configEvent);
		}
		
		private function debugInit():void {
			pointArray = new Array();
			debugMc = new DebugMC();
			
			addChild(debugMc);
		}
		//-----------------------------------------
		private function configConst():void {
			pageList = new Vector.<BasePageViewer>;
			
			preArea=hotArea = 0;
			mouseSpeed = 3;
			flipSpeed=autoSpeed = 2;
			span = 100;
			currentPageNum =nextPageNum= 0;
			
			isFlipping = false;
			isDraging = false;
			isCorner = false;
			isNext = false;
			
			mousePoint = new Point();
			topPoint = new Point(bWidth / 2, 0);
			botPoint = new Point(bWidth / 2, bHeight);
			targetPoint = new Point();
			
			radiusArray = new Array();
			radiusArray.push(bWidth / 2);												//小半径 radiusArray[0];2009-5-9 17:37
			radiusArray.push(MathUtils.distance(0, 0, bWidth / 2, bHeight));		//大半径 radiusArray[1];2009-5-9 17:37
		}
		/*-------------------------------------------
		* 
		* 		This part is for configing Event
		* 
		* ------------------------------------------*/
		private function configEvent(e:Event):void {
			addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
		}
		private function enterFrameHandler(e:Event):void {
			if (hotArea==0||hotArea==1) {
				if (my < 0) {
					tempCenter = botPoint;
					tempRadius = radiusArray[1];
				}else {
					tempCenter = topPoint;
					tempRadius = radiusArray[0];
				}
			}else if (hotArea==2||hotArea==3) {
				if (my < bHeight) {
					tempCenter = botPoint;
					tempRadius = radiusArray[0];
				}else {
					tempCenter = topPoint;
					tempRadius = radiusArray[1];
				}
			}
			if (isCorner) {
				isCorner = checkCorner();
			}
			if (isCorner || isDraging) {
				mx = this.mouseX;
				my = this.mouseY;
				targetPoint = MathUtils.getMousePoint(new Point(mx, my), tempCenter, tempRadius);
			}else if (!isFlipping) {
				setTargetPoint();
				isFlipping = true;
			}
			
			if (Math.abs(mousePoint.x - targetPoint.x) > 0.01) {
				mousePoint.x += (targetPoint.x - mousePoint.x) / flipSpeed;
				mousePoint.y += (targetPoint.y - mousePoint.y) / flipSpeed;
				BookUtils.rotateFlip(book.pageDrag , flipMasker, shadow, mousePoint, hotArea);
			}else if (targetPoint.x <= 0.1 || targetPoint.x >= bWidth - 0.1) {
				endFlip();
			}
			//-------------This is for debug--------------------------
			//pointArray = StaticFunction.getBorderPoint(mousePoint, hotArea, bWidth, bHeight);
			//debugMc.setPoint(mousePoint, pointArray[0], pointArray[1], pointArray[2]);
			//--------------------------------------------------------
			
		}
		private function mouseMoveHandler(e:MouseEvent):void {
			mx = mouseX;
			my = mouseY;
			
			isCorner = checkCorner();
			if (isCorner) {
				switch(hotArea) {
					case 0:
						mousePoint = new Point(0, 0);
						nextPageNum = currentPageNum - 1;
						break;
					case 2:
						mousePoint = new Point(0, bHeight);
						nextPageNum = currentPageNum - 1;
						break;
					case 1:
						mousePoint = new Point(bWidth, 0);
						nextPageNum = currentPageNum + 1;
						break;
					case 3:
						mousePoint = new Point(bWidth, bHeight);
						nextPageNum = currentPageNum + 1;
						break;
				}
				setNextPage();
				
				addEventListener(Event.ENTER_FRAME, enterFrameHandler);
				removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			}
			
		}
		private function mouseDownHandler(e:MouseEvent):void {
			if(isCorner) isDraging = true;
		}
		private function mouseUpHandler(e:MouseEvent):void {
			if (isDraging) {
				isFlipping = true;
				setTargetPoint();
			}
			flipSpeed = autoSpeed;
			isDraging = false;
		}
		/*------------------------------------------
		* 
		* This portion is the main function of detecting the position of mouse
		* 
		* -----------------------------------------*/
		private function checkCorner():Boolean {
			if (isDraging||isFlipping) return false;
			if (mx < 0 ||mx>this.bWidth||my<0||my>this.bHeight) return false;
			
			var mToCornerX:Number = Math.abs((mx - this.x) < this.bWidth / 2?mx:mx-this.bWidth);
			var mToCornerY:Number = Math.abs((my - this.y) < this.bHeight / 2?my:my-this.bHeight);
			
			if (mToCornerX < 50 && mToCornerY < 50) {
				var horizontal:Number = (mx < bWidth / 2)?1:2;
				var vertical:Number = (my < bHeight / 2)?1: -1;
				hotArea = horizontal - vertical;
				flipSpeed = mouseSpeed;
				
				return true;
			}
			return false;
		}
		private function setTargetPoint():void {
			var tempDis = 0.1;
			switch(hotArea) {
				case 0:
				case 2:
					if (mx < span) {
						targetPoint.x = tempDis;
						isNext = false;
					}else {
						targetPoint.x = bWidth-tempDis;
						isNext = true;
					}
					targetPoint.y = (hotArea==0)?0:bHeight;
					break;
				case 1:
				case 3:
					if (bWidth - mx < span) {
						targetPoint.x = bWidth - tempDis;
						isNext = false;
					}else {
						targetPoint.x = tempDis;
						isNext = true;
					}
					targetPoint.y = (hotArea==1)?0:bHeight;
					break;
			}
		}
		private function setNextPage():void {
			flipMasker.init();
			book.setDragPage(nextPageNum, hotArea);
			
			theNextPage = book.pageDrag.clone();
			theNextPage.x = bWidth*(hotArea%2) ;
			theNextPage.position = 1 - hotArea % 2;
			addChildAt(theNextPage, 0);
			
			shadow.scaleX = 1;
		}
		private function endFlip():void {
			removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			removeChild(theNextPage);
			shadow.scaleX = 0;
			
			isFlipping = false;	
			mousePoint = new Point();
			
			book.update(isNext);
			flipMasker.update();
			if (!isNext) return;
			currentPageNum = nextPageNum;
			
		}
		public function addPage(page:BasePageViewer):void {
			if(page is PageViewer) pageList.push(page);
			//book.addPage(page);
			book.init();
		}
		public function nextPage():void {
			gotoPage(currentPageNum + 1);
		}
		public function prevPage():void {
			gotoPage(currentPageNum - 1);
		}
		public function frontCover():void {
			gotoPage(0);
		}
		public function backCover():void {
			gotoPage(pageList.length);
		}
		public function gotoPage(num:Number):void {
			if (isFlipping||isDraging||isCorner) return;
			if (num<0||num>pageList.length||num==currentPageNum) return;
			nextPageNum = num;
			if (nextPageNum > currentPageNum) {
				hotArea = 1;
				mousePoint = new Point(bWidth-200,200);
			}else {
				hotArea = 0;
				mousePoint = new Point(200,200);
			}
			mx = mousePoint.x;
			my = mousePoint.y;
			flipMasker.init();
			setNextPage();
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		public function get pageNum():Number {
			return currentPageNum;
		}
	}
}